AWS x HackerOneのCTFやってみた(writeup) #hacker101
こんにちは、臼田です。
みなさん、AWSのセキュリティ楽しんでますか?(挨拶
今回はHackerOneからAWSのハッキングスキルを試すCTFコンテンツが4/5 - 12の期間限定で公開されていたので挑戦してみました。
Test your AWS hacking skills in our latest #CTF level on #hacker101. Sign in to https://t.co/3oYS1TRLZH to find out more! pic.twitter.com/xuxq4crHkX
— HackerOne (@Hacker0x01) April 6, 2021
Hacker101 CTF概要
最初にコンテンツの紹介を。HackerOneは企業と侵入テスターおよびサイバーセキュリティ研究者をつなぐ脆弱性調整およびバグ報奨金プラットフォームです。(wikipediaより引用)
HackerOneが主催するHacker101はWebセキュリティに関する無料のオンラインコースでビデオレッスンも備えています。コンテンツはBurpプロキシセットアップから、Cookieのセキュリティ、クリックジャッキングや暗号化攻撃など様々あります。その中にHacker101 CTFもあります。
Hacker101 CTF自体は常設されたCTFですが、AWSとコラボした問題は期間限定のようですね。
writeup
以下はwriteup(ネタバレ含む)です。
問題を開始すると専用のURLを発行されます。
アクセスするとWebサイトのURLを入力して動作を確認するページが出てきます。これはもろ…SSRFですね。
http://169.254.169.254/latest/meta-data/iam/security-credentials/
にSubmitするとIAM Role名が返ってきてそれも含めてクレデンシャルが取得できます。
さっくりと取れるなーと思いましたが、これで終わりませんw
取得したクレデンシャルからIAM周りの権限を確認しましたがすべてAccess Deniedで権限が足りませんでした。持っている権限がわからないのでここから手探りです。pacuを使ってクロールしていくとus-west-2
にEC2インスタンスが立っているのが確認できます。
4台あり、うち3台は同じサブネットに所属しています。パブリックIPも持っているのでアクセスしてみると、全てSSRF対象のフロントサイトでした。サイトのDNS名を解決するとまた別のIPが返ってくるので、ALB配下に3台あることが予想できます。直接フロントのEC2にアクセスできるのでそちらの筋も詳細に確認したいですが(多少は確認しましたが)もっと重要なのは残りの1台のEC2です。
プライベートサブネットに設置されていてフロントサイトからアクセスして欲しそうにしています。というわけでリクエストすると以下のように。
200で返ってこないけどWebサービスは生きています。中身を見たいのでchromeのDevToolで眺めていましたが、レスポンスはbase64エンコードされて返ってきます。面倒なのでエラーメッセージが出るjsを書き換えてPreview側に出すようにします。エラーメッセージにはMissing api_key parameter. See AWS SecretsManager.
とやさしいなぁ…
SecretsManagerには3つのパラメーターがあり、web_service_health_api_key
、h101_flag_secret_main
、h101_flag_secret_secondary
と、フラグがチラ見せ。しかしapi_key
しか取得できません。
とりあえず取得したapi_keyを使ってプライベートEC2に引き続きアクセスします。
返ってくるサイトはパット見よくわかりません。
コードを確認するとマシンのステータスを確認して、OK/NGを表示するサイトのようです。しかしマシンのリストはなにもない。htmlに埋め込まれているjsのリンクを確認すると以下のようになっていました。
function authenticated_fetch(addr) { let separator = addr.includes("?") ? "&" : "?"; return fetch(`${addr}${separator}api_key=${api_key}`); } fetch_machines().then((result) => result.json()).then((machine_addrs) => { machine_addrs.forEach((addr) => { fetch_system_status(addr).then((result) => result.json()).then((data) => { let status_table = document.getElementById("status_table"); let status_row = document.createElement("tr"); let machine_addr = document.createElement("td"); machine_addr.textContent = addr; let machine_status = document.createElement("td"); machine_status.textContent = data["success"] ? "OK" : "UNREACHABLE"; machine_status.className = data["success"] ? "ok" : "err"; status_row.appendChild(machine_addr); status_row.appendChild(machine_status); status_table.appendChild(status_row); }) }); });
マシンのリストを確認する/api/get_machines
とステータスを確認する/api/get_status
があります。ステータスを確認する際にaddr
をとっているのでここから更に多段SSRFができそうに。
ちなみにマシン一覧を確認すると500エラーになりました。こっちも使いみちがあるかと思い色々試してみたくなりますが(試しましたが)SSRFします。
http://10.0.0.55/api/get_status?api_key=xxxxxxxxxxxxxxxxx%26addr=169.254.169.254%2Flatest%2Fmeta-data%2Fiam%2Fsecurity-credentials
多段なのでURIエンコードするのと、addr
がこちらはhttp://
がいらないので注意。IAM Role名を取得したらそのままクレデンシャルを取得します。
獲得したクレデンシャルからSecretsManagerのフラグを確認すると、h101_flag_secret_main
は確認できずh101_flag_secret_secondary
のみ取得できました。secondaryだけナンデ?
引き続き取得したクレデンシャルでpacuで色々確認していくと、S3のバケットリストが取得できました。
aws s3 ls 2021-04-07 01:56:17 awsctfelblogs 2021-04-07 13:53:15 awsctfelbqueryresults 2021-03-17 23:04:26 h101-dev-notes 2021-03-17 23:03:20 h101-flag-files 2021-03-17 05:22:02 h101ctfloadbalancerlogs
ここにもいかにもflagが。しかしオブジェクト一覧が取得できたのはh101-dev-notes
のみでした。README.md
があるので取得して中身を見ると、フラグの作り方が書いてありました。
# Flag Generation This document outlines the steps required to generate a flag file. ## Steps 1. Fetch your `hid` and `fid` values from the `/api/_internal/87tbv6rg6hojn9n7h9t/get_hid` endpoint. 2. Send a message to the SQS queue `flag_file_generator` with the following format ```json {"fid": "", "hid": ""} ``` where `` and `` are the values you received in step 1. 3. Get the `.flag` file from the `flag-files` (name may be slightly different) S3 bucket. ## Tips If you've never worked with SQS (Simple Queue Service) before then the [following link](https://docs.aws.amazon.com/cli/latest/reference/sqs/send-message.html) may be helpful in sending messages from the aws cli tool.
SQSを使ってフラグを生成するとかAWSっぽいですね。生成URLにアクセスして2つのidを獲得します。
http://10.0.0.55/api/_internal/87tbv6rg6hojn9n7h9t/get_hid?api_key=xxxxxxxxxxxxxxxxxxxxxxx
取得したらSQSへsend-message
します。一応quere-url
を先に取得しておきます。
aws sqs get-queue-url --queue-name flag_file_generator
aws sqs send-message --queue-url https://us-west-2.queue.amazonaws.com/999999999999/flag_file_generator --message-body '{"fid": "xxxxxxxxxxxxxxxxxxxxxxxx", "hid": "xxxxxxxxxxxxxxxxxxxxxxxx"}'
key名もわかっているのでh101-flag-files
から直接getします。
aws s3api get-object --bucket h101-flag-files --key xxxxxxxxxxxxxxxxxxxxxxx.flag ./flag
取得したフラグを最初のサイトに打ち込んでHacker101 CTFのフラグをゲットです。
ちなみに最初の生成されたURLのサイトで取得したflagじゃないと受け付けないので、サイトをリセットするとflagが通らないので気をつけましょう(1日負け)
まとめ
Hacker101 CTFをやってみました。
普通のWeb問と少し違うAWS問らしい感じでした。欲を言えばもっと現実的な問題も欲しいですが、多段SSRFやSQSでフラグ発行など面白い要素があり楽しめました。
良い子は絶対ユーザーにURLを入力させるサイトを作っちゃだめだぞ!お兄さんとの約束だ!